package com.xqboss.chain.service;

import com.alibaba.fastjson2.JSONObject;
import com.reddate.wuhanddc.DDCSdkClient;
import com.reddate.wuhanddc.dto.ddc.Account;
import com.reddate.wuhanddc.dto.ddc.AccountInfo;
import com.reddate.wuhanddc.dto.ddc.AccountRole;
import com.reddate.wuhanddc.listener.SignEventListener;
import com.xqboss.chain.config.BsnConfig;
import jodd.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * BSN 服务
 * </p>
 *
 * @author Trent
 * @date 2023/8/11
 */
@Service
@Slf4j
public class BsnService {


    @Autowired
    private BsnConfig bsnConfig;

    /**
     * 创建区块链钱包
     *
     * @return
     */
    public Account createAccount() {
        SignEventListener signEventListener = event -> null;
        // ddcSdkClient instantiation
        DDCSdkClient ddcSdkClient = DDCSdkClient.builder().setSignEventListener(signEventListener).build();
        Account account = ddcSdkClient.accountService.createAccount();
        log.info(JSONObject.toJSONString(account));
        return account;
    }

    /**
     * 将区块链账户添加到BSN
     * @param userId 本地用户ID
     * @param address 用户的钱包地址
     */
    public void addAccountToBsn(Long userId, String address) {
        SignEventListener signEventListener = event -> transactionSignature(event.getSender(), event.getRawTransaction());
        DDCSdkClient ddcSdkClient = DDCSdkClient.builder().setSignEventListener(signEventListener).build();

        List<AccountInfo> accounts = new ArrayList<>();
        AccountInfo accountInfo = new AccountInfo();
        accountInfo.setAccountName("xq-" + userId);
        accountInfo.setAccount(address);
        accountInfo.setAccountRole(AccountRole.Consumer);
        accounts.add(accountInfo);
        try {
            String tx = ddcSdkClient.authorityService.addBatchAccountByOperator(bsnConfig.getSendAddress(), accounts);
        } catch (Exception e) {
            // TODO 添加账户失败日志处理
        }
    }

    /**
     * 铸造NFT
     *
     * @param to
     * @param ddcUri 如果要在官方DDC显示出URL，那DDCURI中需增加url或image字段，如ddcURI="{\"url\":\"https://ddc.bsnbase.com/main/index\"}"
     * @param data   附加数据
     * @throws Exception
     */
    public String safeMint(String to, String ddcUri, byte[] data) throws Exception {
        SignEventListener signEventListener = event -> transactionSignature(event.getSender(), event.getRawTransaction());
        DDCSdkClient ddcSdkClient = DDCSdkClient.builder().setSignEventListener(signEventListener).build();
        return ddcSdkClient.ddc721Service.safeMint(bsnConfig.getSendAddress(), to,  ddcUri, data);
    }


    /**
     * NFT转移
     *
     * @param from  拥有者账户
     * @param to    接收者账户
     * @param ddcId DDCID
     * @param data  附加数据
     * @return 转移结果
     * @throws Exception Exception
     */
    public String safeTransferFrom(String fromPrivate, String from, String to, BigInteger ddcId, byte[] data) throws Exception {
        SignEventListener signEventListener = event -> transactionSignature(fromPrivate, event.getRawTransaction());
        DDCSdkClient ddcSdkClient = DDCSdkClient.builder().setSignEventListener(signEventListener).build();
        String tx = ddcSdkClient.ddc721Service.safeTransferFrom(from, from, to, ddcId, data);
        log.info(tx);
        return tx;
    }


    /**
     * 签名交易
     *
     * @param sender
     * @param transaction
     * @return
     */
    public String transactionSignature(String sender, RawTransaction transaction) {
        // sender: Obtain the private key according to the sender and complete its signature
        //sender privateKey
        Credentials credentials = null;
        if (StringUtil.isNotBlank(sender) && sender.length() == 66) {
            credentials = Credentials.create(sender);
        } else {
            credentials = Credentials.create(bsnConfig.getPrivateKey());
        }
        byte[] signedMessage = TransactionEncoder.signMessage(transaction, 5555, credentials);
        return Numeric.toHexString(signedMessage);
    }

    /**
     * 给用户充值量能
     * @param address 充值的地址
     * @param amount 充值的金额
     * @return  交易hash
     * @throws Exception
     */
    public String recharge(String address, BigInteger amount) throws Exception {
        SignEventListener signEventListener = event -> transactionSignature(event.getSender(), event.getRawTransaction());
        DDCSdkClient ddcSdkClient = DDCSdkClient.builder().setSignEventListener(signEventListener).build();
        return ddcSdkClient.chargeService.recharge(bsnConfig.getSendAddress(), address, amount);
    }

    /**
     * 获取账户能量值
     * @param address
     * @return
     * @throws Exception
     */
    public BigInteger getAccountBalance(String address) throws Exception {
        SignEventListener signEventListener = event -> transactionSignature(event.getSender(), event.getRawTransaction());
        DDCSdkClient ddcSdkClient = DDCSdkClient.builder().setSignEventListener(signEventListener).build();
        return ddcSdkClient.chargeService.balanceOf(address);
    }
}
